package mario.game.graymachine.core;

import mario.game.graymachine.R;
import mario.game.graymachine.sprite.GLSprite;
import mario.game.graymachine.sprite.Player;
import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.os.Handler.Callback;
import android.util.Log;
import android.view.MotionEvent;

public class MoveEngine implements Runnable ,SensorEventListener{
	public static final String TAG="g-ray";
	private Scene mScene;//current scene;
	Player player;
	private SensorManager mSensorMgr;
	private Sensor mOriSensor;
	private boolean stopFlag;
	private boolean waitFlag;
	private Context context;
	private OpenGLTestActivity.GameMsgHandler mGameMsgHandler;
	public MoveEngineMsgHandler mMoveEMsgHandler;

	public MoveEngine(Context c){
		context=c;
		mGameMsgHandler=((OpenGLTestActivity)context).getGameMsgHandler();
//		mMoveEMsgHandler=new MoveEngineMsgHandler();
		
//		initListener();
	}
	private void initListener() {

		mSensorMgr= (SensorManager)context.getSystemService(Activity.SENSOR_SERVICE);
		mOriSensor= mSensorMgr.getSensorList(Sensor.TYPE_ORIENTATION).get(0);
		
	}
	public void run() {
//		Looper.prepare();
		/**
		 * background
		 */
		GLSprite spri;//a temp referance to sprites, avoid allocate memory in game time.
		GLSprite bullet; // a temp referance to bullets.

            ProfileRecorder.sSingleton.start(ProfileRecorder.PROFILE_SIM);
			int x=mScene.bg1CamaraX>>3;
			if(x==(int)mScene.bg1[0].width){
				mScene.bg1group=mScene.bg1[0];
				mScene.bg1[0]=mScene.bg1[1];
				mScene.bg1[1]=mScene.bg1group;
				mScene.bg1CamaraX=0;
			}
			mScene.bg1[0].x=-x;
			mScene.bg1[1].x=mScene.bg1[0].width-x;
			
			mScene.bg1CamaraX+=mScene.bg1CamaraXIncrement;
			
			/**
			 * sprites action
			 */
			player.update(20);
			for(int i=0;i<mScene.MAX_SPRITS;i++){
				spri = mScene.mSprites[i];
				if(spri!=null&&!spri.isDead){
					spri.update(20);
					if(collisionDetect(player, spri)&&!player.isDead){
						player.collisionWith(spri);
					}
				}
			}
			for(int i=0;i<mScene.MAX_BULLETS;i++){
				bullet = mScene.mBullets[i];
				if(bullet!=null&&!bullet.isDead){
					bullet.update(20);
					//detect spri bullets collision to player:
					if(!player.isDead&&collisionDetect(player, bullet)){
						player.collisionWith(bullet);
					}
					//detect player bullets collision to spri:
					for(GLSprite sp: mScene.mSprites){
						if(sp!=null&&!sp.isDead&&collisionDetect(sp, bullet)){
							if(sp.collisionWith(bullet)){
								Message msg = Message.obtain();
								msg.what=GConstant.SOUND;
								msg.obj=2;
								mGameMsgHandler.sendMessage(msg);

							}
//							xx
						}
					}
				}
			}
			mScene.update();
			waitFlag=true;

			
			/**
			 * record FPS
			 */
			ProfileRecorder.sSingleton.stop(ProfileRecorder.PROFILE_SIM);
			ProfileRecorder.sSingleton.recordFPS();
			while(count--==0){
				Message msg = Message.obtain();
				msg.what=GConstant.FPS;
				msg.obj=ProfileRecorder.sSingleton.getFPS();
				mGameMsgHandler.sendMessage(msg);
				count=10;
			}
//		}
	}
	//use to report fps every 10 frames
	int count=10;
	
	
	float fTmp1,fTmp2,fTmp3,fTmp4;
	private boolean collisionDetect(GLSprite spri1,GLSprite spri2){
		int x1=(int) (spri1.x+spri1.width/2);
		int x2=(int) (spri2.x+spri2.width/2);
		int y1=(int) (spri1.y+spri1.height/2);
		int y2=(int) (spri2.y+spri2.height/2);
		int cw=(spri1.cwidth+spri2.cwidth);
		int ch=(spri1.cheight+spri2.cheight);
		if(Math.abs(x1-x2)<cw&&(Math.abs(y1-y2)<ch))
			return true;
		return false;
	}

	/**
	 * 
	 */
	
	public void switchTo(Scene s){
		mScene=s;
		init();
		player=mScene.player;
		player.mGameMsgHandler=mGameMsgHandler;
	}
	
	public void init(){
		mScene.setup();
	}

	public void onAccuracyChanged(Sensor sensor, int accuracy) {
		// TODO Auto-generated method stub
		
	}
	
	static final int SENSOR_VALUE_LENGTH=20;
	static int[] pitchValues=new int[SENSOR_VALUE_LENGTH],rollValues=new int[SENSOR_VALUE_LENGTH];
	static int index=0;
	public void onSensorChanged(SensorEvent event) {
		
		pitchValues[index]=(int) event.values[1];
		rollValues[index]=(int) event.values[2];
		analyzeSensorPitch();
		analyzeSensorRoll();
		
		
		index++;
		if(index==SENSOR_VALUE_LENGTH){
			index=0;
		}
	}
	/**
	 *  anlyze the left&right state
	 * @param values the values from last few times' SensorEvent.values[2]
	 */
	private void analyzeSensorPitch(){
		if(index!=0){
			//varrible from last value.
			int var=pitchValues[index]-pitchValues[index-1];
			if(var>1||pitchValues[index]>10){
				mScene.player.pushRight();
				return;
			}else if(var<-1||pitchValues[index]<-6){
				mScene.player.pushLeft();
			}else{
				mScene.player.releaseLeft();
			}
		}
		
	}
	/**
	 * anlyze the up&down state,
	 * @param values the values from last few times.
	 */
	private void analyzeSensorRoll(){
		if(index!=0){
			//varrible from last value.
			int var=rollValues[index]-rollValues[index-1];
			int avg=avgVal(rollValues);
			if(var>0||rollValues[index]>55){
				mScene.player.pushUp();
			}else if(var<0||rollValues[index]<40){
				mScene.player.pushDown();
			}else{
				mScene.player.releaseDown();
			}
		}
	}
	
	private int avgVal(int[] val) {
		int sum = 0;
		for(int i =0;i<val.length;i++){
			sum+=val[i];
		}
		
		return sum/val.length;
	}
	public void surfaceCreated(){
//		registEventListener();
	}
	
	
	public void surfaceDestroyed(){
//		unregistEventListener();
		stopFlag=true;
	}
	private void registEventListener() {
		mSensorMgr.registerListener(this, mOriSensor, SensorManager.SENSOR_DELAY_FASTEST);
	}
	private void unregistEventListener() {
		mSensorMgr.unregisterListener(this);
	}
	public void setScene(Scene scene) {
		mScene=scene;
		player=mScene.player;
		player.mGameMsgHandler=mGameMsgHandler;
	}
	public void onresume() {
		synchronized (this) {
			waitFlag=false;
			notify();
		}
	}
	
	public class MoveEngineMsgHandler extends Handler{
		public MoveEngineMsgHandler(Looper looper) {
			super(looper);
			Log.i("ddd_____","handler looper:"+looper);
		}

		@Override
		public void handleMessage(Message msg) {
			switch (msg.what){
			case GConstant.PLAYER_DEAD:
				stopFlag=true;
				break;
			case GConstant.TRACKBALL:
				palyTrackballAction(msg.obj);
				break;
			case GConstant.TOUCH:
				Log.i("ddd_____","handler got msg:"+Thread.currentThread());
				touch();
				break;
			default:
				break;
			}
		}
		public void touch(){
			switch(player.powerType){
			case 1:  
				GLSprite catchSpri = playerActionCatchDetect();
				if(catchSpri!=null){
					player.grap(catchSpri);
					Log.d(TAG, "got a spri");
					Message msg = Message.obtain();
					msg.what=GConstant.SOUND;
					msg.obj=R.raw.aaa;
					mGameMsgHandler.sendMessage(msg);
					mGameMsgHandler.sendEmptyMessage(GConstant.PROGRESS_SET_ZERO);
				}else{
					Log.d(TAG, "got nothing");
					Message msg = Message.obtain();
					msg.what=GConstant.SOUND;
					msg.obj=1;
					mGameMsgHandler.sendMessage(msg);
				}
				break;
			case 2:
				player.pushAttack();
			}
		}

	}
	private GLSprite playerActionCatchDetect(){
		for(int i =0;i<mScene.mSprites.length;i++){
			if(mScene.mSprites[i]!=null&&!mScene.mSprites[i].isDead){
				fTmp1=(mScene.mSprites[i].x+mScene.mSprites[i].width/2);
				fTmp2=(player.x+player.width/2);
				fTmp3=(mScene.mSprites[i].y+mScene.mSprites[i].height/2);
				fTmp4=(player.y+player.height/2);
				if((fTmp2-fTmp1>(mScene.mSprites[i].cwidth+player.cwidth)&&fTmp2-fTmp1<(mScene.mSprites[i].cwidth+player.cwidth+10))
						&&(Math.abs(fTmp3-fTmp4)<(mScene.mSprites[i].cheight+player.cheight))){
					GLSprite tmp = mScene.mSprites[i];
					mScene.mSprites[i]=null;
					return tmp;
				}
			}
		}
		return null;
	}
	MotionEvent motion;
	private void palyTrackballAction(Object obj) {
		motion = (MotionEvent)obj;
		float x =motion.getX();
		float y =motion.getY();
		if(x>0){
			player.pushRight();
		}
		if(x<0){
			player.pushLeft();
		}
		if(y>0){
			player.pushDown();
		}
		if(y<0){
			player.pushUp();
		}
		player.setMoveTime();
	}
	public void setloop(Looper loop) {
		mMoveEMsgHandler=new MoveEngineMsgHandler(loop);
		
	}

}
